#include"Tcpserver.h"
#include"Logger.h"
#include"TcpConnection.h"

#include<functional>
#include<strings.h>


static Eventloop* CheckLoopNotNull(Eventloop *loop)
{
    if(loop==nullptr)  
    {
        LOG_FATAL("%s:%s:%d mainLoop is null \n",__FILE__,__FUNCTION__,__LINE__);
    }
    return loop;
} 
Tcpserver::Tcpserver(Eventloop *loop,
    const InetAddress &listenAddr,
    const std::string &nameArgs,
    Option option)
        :loop_(CheckLoopNotNull(loop))
        ,ipPort_(listenAddr.toIpPort())
        ,name_(nameArgs)
        ,acceptor_(new Acceptor(loop,listenAddr,option==kReusePort))
        ,threadPool_(new EventloopThreadPool(loop,name_))
        ,connectionCallback_()
        ,messageCallback_()
        ,nextConnId_(1)
        ,started_(0)
        {
            //当有新用户连接时，将执行TcpServer::newConnection回调
            acceptor_->setNewConnectionCallback(std::bind(&Tcpserver::newConnection,this,
                       std::placeholders::_1,std::placeholders::_2 ));
        }

void Tcpserver::setThreadNum(int numThreads)
{
    threadPool_->setThreadNum(numThreads);
}
void Tcpserver::start()
{
    if(started_++==0)//防止一个Tcpserver对象被start多次
    {
        threadPool_->start(threadInitCallback_);//启动底层的线程池
        loop_->runInLoop(std::bind(&Acceptor::listen,acceptor_.get()));
    }
}

//有一个新的客户端连接，acceptor会执行这个回调操作
void Tcpserver::newConnection(int sockfd,const InetAddress &peerAddr)
{
    //轮循算法，选择一个subloop管理channel
    Eventloop *ioLoop=threadPool_->getNextloop();
    char buf[64]={0};
    snprintf(buf,sizeof buf,"-%s#%d ",ipPort_.c_str(),nextConnId_);
    ++nextConnId_;
    std::string connName=name_+buf;
    LOG_INFO("TcpAerver::newConnection [%s] - new connrction [%s] from %s \n",
        name_.c_str(),connName.c_str(),peerAddr.toIpPort().c_str());

    //通过sockfd获取其绑定的本机的ip地址和端口信息
    sockaddr_in local;
    ::bzero(&local,sizeof local);
    socklen_t addrlen=sizeof local;
    if(::getsockname(sockfd,(sockaddr*)&local,&addrlen)<0)//获取当前套接字在本地的ip和端口号
    {
        LOG_ERROR("sockets::getLocalAddr");
    }

    InetAddress localAddr(local);
    //根据连接成功的sockfd，创建TcpConnection连接对象
    TcpConnectionPtr conn(new TcpConnection(
                            ioLoop,
                            connName,
                            sockfd,
                            localAddr,
                            peerAddr));
    connections_[connName]=conn;

    //下面的回调都是用户设置给TcpServer=>TcpConnection=>Channel=>Poller=>notify channel调用回调
    conn->setConnectionCallback(connectionCallback_);
    conn->setMessageCallback(messageCallback_);
    conn->setWriteCompleteCallback(writeCompleteCallback_);

    conn->setCloseback(
        std::bind(&Tcpserver::removeConnection,this,std::placeholders::_1)
    );
    ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished,conn));
}

void Tcpserver::removeConnection(const TcpConnectionPtr &conn)
{
  loop_->runInLoop(
    std::bind(&Tcpserver::removeConnectionInLoop,this,conn)
  );
}

void Tcpserver::removeConnectionInLoop(const TcpConnectionPtr &conn)
{
    LOG_INFO("TcpServer::rempveConnectionInLoop [%s] - connection %s \n",name_.c_str(),conn->name().c_str());
    connections_.erase(conn->name());
    Eventloop *ioloop=conn->getloop();
    ioloop->queueInLoop(
        std::bind(&TcpConnection::connectDestroyed,conn)
    );
}
Tcpserver::~Tcpserver()
{
    for(auto &item : connections_)
    {
        TcpConnectionPtr conn(item.second);//好处：这个局部的shared_ptr智能指针对象，出右括号可以自动释放new出来的TcpConnection对象资源了
        item.second.reset();


        //销毁链接
        conn->getloop()->runInLoop(
            std::bind(&TcpConnection::connectDestroyed,conn)
        );
    }
}